/*
 * chunkserver-journal.h
 *
 *  Created on: Jun 16, 2016
 *      Author: zhangzm
 */

#ifndef CHUNKSERVER_JOURNAL_H_
#define CHUNKSERVER_JOURNAL_H_

#include <stdio.h>
#include <st.h>
#include <stdint.h>
#include <stdbool.h>
#include "st.h"
#include "../ursax-list.h"

#ifdef __cplusplus
extern "C" {
#endif

#define JOURNAL_META_NB_DEFAULT (2*1024)
#define JOURNAL_META_SIZE_DEFAULT (JOURNAL_META_NB_DEFAULT * 32) // 64 / 8 = 8M
#define JOURNAL_CLUSTER_DEFAULT_NB (25*1024) // 8G * 25 = 200G

struct ChunkServerJournal;
typedef void (*request_cb_t)(void* data);
typedef int (*be_chunk_pread_t)(void* chunk, void* buf, uint32_t size, uint32_t offset, void* mmap_ptr);
typedef int (*write_back_jouranl_cb_t)(uint32_t volumeid, uint32_t index, void* buf, off_t offset, size_t towrite, uint64_t version, bool inc_version, bool just_write_data);
typedef struct JMeta
{
	uint32_t volumeid;
	uint32_t index;
	uint32_t begin;
	uint32_t length;
	union{
		time_t time;
		struct {
			uint64_t time0:31;
			uint64_t direct_write_chunk:1;
		};
	};
	uint64_t version;
} __attribute__ ((packed)) JMeta;

struct IORequest
{
	struct JMeta jmeta;
	void* buf;
	request_cb_t cb;
	void* data;
	bool emergency_io;
	char io_type;
	be_chunk_pread_t readfun;
	void* chunk;
	// input output line
	union{
		uint64_t real_meta_file_offset;
		void* meta_addr;
	};
	uint32_t cluster_index;
	uint64_t real_file_offset;
	ssize_t req_ret;
	bool done;
	UrsaXList list;
	void *j;
};

typedef int (*journals_cb_t)(void* journanls, int nb, off_t journal_offset, void* data);
int journal_meta_blocks_do(struct ChunkServerJournal* j, journals_cb_t jcb, void* data);
uint64_t journal_meta_block_nb(void* _j);

#define IO_READ (0)
#define IO_WRITE (1)
bool check_journal(char* ckroot);
struct ChunkServerJournal *get_big_journal(char use_journal_hint);
void set_big_journal(struct ChunkServerJournal *journal);
int create_journal(char *ckroot);
int create_journal_link(char *ckroot, char* realpath);
int create_journal_with_path(char *journal_path);
void rotate_chunkserver_journal(struct ChunkServerJournal* j);
void set_journal_rotate_size(uint64_t size);
void set_journal_size(uint64_t journal_file_size, uint32_t journal_meta_nb);
struct ChunkServerJournal* init_chunkserver_journal(char *ckroot, write_back_jouranl_cb_t wbj_cb);
void fini_chunkserver_journal(struct ChunkServerJournal* j);
int commit_IO_request(struct ChunkServerJournal* j, struct IORequest *req);
int get_chunk_version_range_from_journal(struct ChunkServerJournal* j, uint32_t volumeid, uint32_t index, uint64_t *start_version, uint64_t *end_version);
int get_journal_reference(struct ChunkServerJournal* j);
void start_journal_control_thread();

int async_chunk_pwrite(struct ChunkServerJournal* j, struct IORequest *req, uint32_t volumeid, uint32_t index,
						const void *buf, size_t count, off_t offset, uint64_t version, time_t time);
int async_chunk_pread(struct ChunkServerJournal* j, struct IORequest *req, be_chunk_pread_t fun, void* chunk,
					uint32_t volumeid, uint32_t index, void *buf, size_t count, off_t offset);
ssize_t sync_chunk_pread(struct ChunkServerJournal* j, be_chunk_pread_t fun, void* chunk,
						uint32_t volumeid, uint32_t index, void *buf, size_t count, off_t offset);
ssize_t sync_chunk_pwrite(struct ChunkServerJournal* j, uint32_t volumeid, uint32_t index,
							const void *buf, size_t count, off_t offset, uint64_t version, time_t time);
ssize_t sync_chunk_write_version(struct ChunkServerJournal* j, uint32_t volumeid, uint32_t index,
								uint32_t chunk_size, uint64_t version);

#ifdef __cplusplus
}
#endif

#endif /* CHUNKSERVER_JOURNAL_H_ */
